This page last changed on Nov 30, 2004 by jcarreira.

Consider adding transparent i18 with simple on-the-fly locale switching to your appliction via I18NInterceptor.

The main idea:
Interceptor could track locale switch requests, persist selection in current session and set locale for all (or appropriate) actions invoked.
package neuro.util.xwork;

import com.opensymphony.xwork.ActionSupport;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.xwork.interceptor.Interceptor;

import java.util.Locale;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * I18nInterceptor
 * @author Aleksei Gopachenko
 */
public class I18nInterceptor implements Interceptor
{
    protected static final Log log = LogFactory.getLog(I18nInterceptor.class);

    public static final String DEFAULT_SESSION_ATTRIBUTE = "WW_TRANS_I18N_LOCALE";
    public static final String DEFAULT_PARAMETER = "request_locale";

    protected String parameterName = DEFAULT_PARAMETER;
    protected String attributeName = DEFAULT_SESSION_ATTRIBUTE;

    /**
     */
    public I18nInterceptor()
    {
        if(log.isDebugEnabled()) log.debug("new I18nInterceptor()");
    }

    public void setParameterName(String parameterName) {
        this.parameterName = parameterName;
    }

    public void setAttributeName(String attributeName) {
        this.attributeName = attributeName;
    }

    /**
     */
    public void init() {
        if(log.isDebugEnabled()) log.debug("init()");
    }

    /**
     */
    public void destroy() {
        if(log.isDebugEnabled()) log.debug("destroy()");
    }

    /**
     */
    public String intercept(ActionInvocation invocation) throws Exception {
        if(log.isDebugEnabled()) log.debug("intercept '"
            +invocation.getProxy().getNamespace()+"/"
            +invocation.getProxy().getActionName()+"' { ");

        //get requested locale
        Object requested_locale = invocation.getInvocationContext().getParameters().get(parameterName);
        if(requested_locale!=null && requested_locale.getClass().isArray() && ((Object[])requested_locale).length==1) {
            requested_locale=((Object[])requested_locale)[0];
        }
        if(log.isDebugEnabled()) log.debug("requested_locale="+requested_locale);
        //save it in session
        if (requested_locale!=null) {
            Locale locale = (requested_locale instanceof Locale)? 
              (Locale) requested_locale : localeFromString(requested_locale.toString());
            if(log.isDebugEnabled()) log.debug("store locale="+locale);
            if(locale!=null)invocation.getInvocationContext().getSession().put(attributeName,locale);
        }
        //set locale for action
        Object locale = invocation.getInvocationContext().getSession().get(attributeName);
        if (locale!=null && locale instanceof Locale) {
            if(log.isDebugEnabled()) log.debug("apply locale="+locale);
            invocation.getInvocationContext().setLocale((Locale)locale);
        }

        if(log.isDebugEnabled()) log.debug("before Locale="+((ActionSupport)invocation.getAction()).getLocale());
        final String result = invocation.invoke();
        if(log.isDebugEnabled()) log.debug("after Locale="+((ActionSupport)invocation.getAction()).getLocale());

        if(log.isDebugEnabled()) log.debug("intercept } ");
        return result;
    }

    Locale localeFromString(String localeStr) {
        if ((localeStr == null) || (localeStr.trim().length() == 0) || (localeStr.equals("_"))) {
            return Locale.getDefault();
        }
        int index = localeStr.indexOf('_');
        if (index < 0) {
            return new Locale(localeStr);
        }
        String language = localeStr.substring(0,index);
        if (index == localeStr.length()) {
            return new Locale(language);
        }
        localeStr = localeStr.substring(index +1);
        index = localeStr.indexOf('_');
        if (index < 0) {
            return new Locale(language,localeStr);
        }
        String country = localeStr.substring(0,index);
        if (index == localeStr.length()) {
            return new Locale(language,country);
        }
        localeStr = localeStr.substring(index +1);
        return new Locale(language,country,localeStr);
    }

}

Can be enabled for whole package via something like:
<interceptor name="i18n" class="neuro.util.xwork.I18nInterceptor">
    <!-- on which request parameter we should react, optional, defaults to "request_locale" ->
    <param name="parameterName">set_locale</param>
    <!- under which session attribute locale should be stored, optional, defaults to "WW_TRANS_I18N_LOCALE" ->
    <param name="attributeName">ww_locale</param>
</interceptor>

<interceptor-stack name="i18nStack">
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="defaultStack"/>
</interceptor-stack>

<default-interceptor-ref name="i18nStack"/>

...and invoked in web-app just by adding few links to menu:
<a href="?set_locale=en">EN</a>
<a href="?set_locale=ru">RU</a>
<!- etc -->

Of course you still need to move all explisitly defined messages or labels to appropriate ResourceBundles and make translations. Be sure to check out your
  • Actions - to use getText(...)
  • *-validation.xml files - to use <message key=...>
  • results/views - to use WW i18n services by <webwork:text ...> tag, or directly by evaluating getText(...) OGNL expression on current stack.

If this Interceptor is generally useful, may be it should go into codebase?

Document generated by Confluence on Dec 14, 2004 16:36